#!/usr/bin/python
import re
import os
from itertools import *
import collections

def iscrc(line):
    if re.match("[A-Fa-f0-9]{8}",line):
        return True
    else:
		return False

class Quality():
    resolution=0
    codec=0
    hq=0
    ext=0
    codecs={"xvid":-10,"h264":10,"x264":10,"theora":10}
    extensions={"mkv":10,"avi":-10,"ogm":-10}
    def set_resolution_p(self,resolution_p):
        self.resolution=resolution_p*resolution_p*16/9

    def set_quality(self,quality):
        pass

    def set_resolution(self,x,y):
        self.resolution=int(x)*int(y)

    def set_hq(self,string):
        if string.lower() == "hq":
            self.hq=1
        if string.lower()== "lq":
            self.hq=-1

    def set_codec(self,codec):
        for c in self.codecs:
            if c in codec.lower():          
                self.codec+=self.codecs[c]

    def is_codec(self,codec):
        for c in self.codecs:
            if c in codec.lower():          
                return True
            else:
                return False

    def set_ext(self,ext):
        self.ext=self.extensions.get(ext.lower(),0)

    def relative_value(self):
        return sum(self.resolution,self.codec,self.hq*10,self.ext)
    

class File_Info():
    def __init__(self,path,filename):
        self.crc=None
        self.title=None
        self.subber=None
        self.text=None
        self.extension=None
        self.episode=None
        self.quality=Quality()
        self.filename=filename
        self.path=path
        objects,extension=name_split(filename)
        first_braces=True
        for obj in objects:
            if not obj:#skip spacers & empty
                continue
            if len(obj)>2 and ( obj[0] in "[("):
                content=obj[1:-1]
                if iscrc(content):
                    self.add_crc(content)
                    first_braces=False
                    continue
                if self.isquality(content): #looks like quality, accept as quality and do not set a braces flag
                    self.quality.set_quality(content)
                    first_braces=False
                    continue
                if first_braces : #first braces in name - fansubber name
                    self.add_subber(content)
                    first_braces=False
                    continue
                else:
                    self.add_text(obj)
                    first_braces=False
                    continue
            for inner in re.split("(.+?)(\d+\-?v?\d+?)(\D*)$",obj):
            # shall snatch foo 2, foo 2v2, foo 3-4, foo 014-106v2.
                if inner:
                    inner=inner.strip()
                if not inner: 
                    continue
                if (not self.episode) and self.title:
                    if re.match("\d+",inner):
                        self.add_episode(inner)
                        continue
                else:	
                    clear=re.sub("[\t\s\~\-\_\.]+"," ",inner).strip()
                    if clear:
                        if not self.title:
                            self.add_title(clear)
                        else:
                            self.add_text(clear)
                            continue
        if extension:
            self.add_extension(extension)
            self.quality.set_ext(extension)

    def setup_subbers(self,favorite={},ban=()):
        self.subber_favorite=favorite
        self.subber_ban=ban
        

    def add_crc(self,crc):
        if not self.crc:
            self.crc=crc
        else:
            print "Second crc in ",self.filename
    def add_subber(self,subber):
        if not self.subber:
            self.subber=subber
        else:
            raise TypeError
    def add_text(self,text):
        if self.text:
            self.text.append(text)
        else:
            self.text=[text]
    def add_episode(self,episode):
        if not self.episode:
            self.episode=episode
        else:
            raise TypeError
    def add_title(self,title):
        if not self.title:
            self.title=title
        else:
            raise TypeError
    def add_extension(self,extension):
        if not self.extension:
            self.extension=extension
        else:
            raise TypeError
    quality_patterns={
        "H264":100,
        "H.264":100,
        "X264":100,
        "XVID":-50,
        "BLU":200,
        "BD":200,
        "DIVX":0,
        "AC3":+10,
        "AAC":+10,
        "VORBIS":+10,
        "WMV":-200,
        "HQ":+100,
        "LQ":-300, 
        "DVD":+50,
        "HD":+200,
        "SD":0,
        "FULLHD":+500,
        "FHD":+500,
    }
    resolution_pattern1=r"(\d{3,4})X(\d{3,4})"
    resolution_pattern2=r"(\d{3,4})([PI])"
    extension_patterns={
        "AVI":-10,
        "MP4":-10,
        "MKV":50,
        "OGM":-50,
        "WMV":-200,
        "RM":-300,
        "FLV":-200
    }
    def isquality(self,line):
        test=line.upper()
        if re.search(self.resolution_pattern1,test) or re.search(self.resolution_pattern2,test):
            return True
        for text in self.quality_patterns.keys():
            if text in test:
                return True
        return False
    def quality_weight(self):
        weight=1000
        if self.text:
            for q in self.text:
                q=q.upper()
                res=re.search(self.resolution_pattern1,q)
                if res:
                    weight+=int(res.group(1))*int(res.group(2))/2000-490
                res=re.search(self.resolution_pattern2,q)
                if res:
                    subweight=(int(res.group(1))-720)*1.4
                    if res.group(2).lower()=="i":
                        subweight-=400
                    weight+=subweight
                for pattern,subweight in self.quality_patterns.items():
                    if pattern in q.lower():
                        weight+=subweight
        if self.extension:
            for ext,subweight in self.extension_patterns.items():
                if ext in self.extension.upper():
                    weight+=subweight
        return weight 

    def __cmp__ (self,second):
        return cmp(self.quality_weight(),second.quality_weight())


def name_split(name):
    last_dot=name.rfind(".")
    if last_dot!=-1:
        splited_name=re.split("(\(.+?\))|(\[.+?\])",name[:last_dot])
        extension=name[last_dot:]
    else:
        splited_name=re.split("(\(.+?\))|(\[.+?\])",name)
        extension=None

    return splited_name,extension

class TitleList(dict):
    def add_file(self,file_info):
        if self.has_key(file_info.title):
            if self[file_info.title].has_key(file_info.episode):
                self[file_info.title][file_info.episode].append(file_info)
            else:
                self[file_info.title][file_info.episode]=[file_info,]
        else:
            self[file_info.title]=dict()
            self[file_info.title][file_info.episode]=[file_info,]


class TitleFilter():
    def __init__(self, title_list=(),favorite=[],ban=[]):
        self.title_list=dict(title_list)
        self.favorite=tuple((x.upper() for x in favorite))
        self.ban=tuple((x.upper() for x in ban))

    def check(self,title):
        t=File_Info("",title)
        fav_weight=0
#        print t.subber, t.title, t.episode
#        for j in self.ban: 
#            print j
#        try:
#            print t.subber.upper() in self.ban
#        except:
#            pass
        if t.subber:
            if t.subber.upper() in self.ban:
                print "reason:", t.subber, "is banned"
                return False
            if t.subber.upper() in self.favorite: #replace with dict
                fav_weight=500                
        if not t.title or not t.episode:
            return None
        try:
            m=max(self.title_list[t.title][t.episode])
            if m.quality_weight()<=(t.quality_weight()+fav_weight):
                return True
            else:
                print "reason:", m.filename, "is exist (totally: %d)"%(len(self.title_list[t.title][t.episode]),)
                return False
        except: #accept all unknown files
            return True 


def test1(source_path,target_path):
#    source_path=("/media/in/anime/in","/media/in/anime/ongoing","/media/in/anime/uncomplete")
#    target_path=("/media/in/anime/ongoning")
    title_list=TitleList()
    for test in source_path:
        for root,dirs,files in os.walk(test):
            for f in files:    
                title_list.add_file(File_Info(root,f))
    
    for title_name,episodes in title_list.iteritems():
        if not title_name:
            print episodes[0][0].filename,"skipped"
            continue
        for episode,files in episodes.iteritems():
            if not episode:
                print files[0].filename,"skipped"
                continue            
            files.sort()
            if len(files)>1:
                print "%s - %s"%(title_name,episode),":",os.path.join(files[0].path,files[0].filename), files[0].quality_weight(),"\n\tDropped:"
                for f in files:
                    print "\t\t",os.path.join(f.path,f.filename),f.quality_weight()
#            for f in files:
#               print "\t  ",f.filename, f.quality_weight()

def test2(source_path,target_path,favorite,ban):
    all_title_list=TitleList()
    test_title_list=TitleList()
    for test in source_path+target_path:
        for root,dirs,files in os.walk(test):
            for f in files:    
                all_title_list.add_file(File_Info(root,f))

    title_filter=TitleFilter(all_title_list,favorite,ban)
    for test in source_path:
        for root,dirs,files in os.walk(test):
            for f in files:
                result=title_filter.check(f)
                if result == True:
                    print "[PASS]", os.path.join(root,f)
                if result == False:
                    print "[SKIP]", os.path.join(root,f)
                if result==None:
                    print "[UNKN]", os.path.join(root,f)                           


if __name__=='__main__':
    source_path=("/media/in/anime/in","/media/in/anime/ongoing","/media/in/anime/uncomplete")
    target_path=("/media/in/anime/ongoing",)
    favorite=("gg","Triad","Vegapunk","DB","Shin-getter","Live-Evil","C-A","Central Anime","Forstii","Chihiro","AniYoshi")
    ban=("Troll-sub","C-W","C_W")
    test2(source_path,target_path,favorite,ban)

